﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace homework5
{
    public partial class Form1 : Form
    {
        //发送http请求
        private HttpClient httpClient;

        //线程安全的字典 用于存储电话号码和与其相关联的url列表
        private ConcurrentDictionary<string, List<string>> phoneNumbers;

        //存储已经爬取过的url列表
        private ConcurrentBag<string> crawledUrls;

        public Form1()
        {
            InitializeComponent();
            httpClient = new HttpClient();
            phoneNumbers = new ConcurrentDictionary<string, List<string>>();
            crawledUrls = new ConcurrentBag<string>();
            
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private async void  btnSearch_Click(object sender, EventArgs e)
        {
            string keyword=txtKeyword.Text.Trim();
            if(string.IsNullOrEmpty(keyword) )
            {
                MessageBox.Show("please input keyword");
                return;
            }

            btnSearch.Enabled = true;
            lstUrls.Items.Clear();
            dgvPhoneNumbers.Rows.Clear();
            //重新初始化已爬取的url集合
            crawledUrls= new ConcurrentBag<string>();
            List<string>searchUrls=GenerateSearchUrls(keyword);
            List<Task> tasks = new List<Task>();
            foreach(var url in searchUrls)
            {
                tasks.Add(ProcessSearchEngineAsync(url));//启动异步处理
            }
            // 等待所有搜索引擎的处理任务完成
            await Task.WhenAll(tasks);

            // 在DataGridView中显示提取的电话号码及其关联的URL
            foreach (var kvp in phoneNumbers)
            {
                dgvPhoneNumbers.Rows.Add(kvp.Key, string.Join(", ", kvp.Value));
            }

            // 启用搜索按钮
            btnSearch.Enabled = true;

            // 提示用户爬取完成
            MessageBox.Show("爬取完成！");
        }

        //处理单个引擎的搜索结果
        private async Task ProcessSearchEngineAsync(string searchurl)
        {
            try
            {
                //发送get请求获取搜索结果页面的html内容
                string html = await httpClient.GetStringAsync(searchurl);

                List<string> resultUrls = ExtraUrls(html);

                // 创建一个任务列表，用于存储所有页面的处理任务
                List<Task> pageTasks = new List<Task>();
                // 遍历每个提取的URL
                foreach (var url in resultUrls)
                {
                    // 检查该URL是否已经被爬取过，避免重复
                    if (!crawledUrls.Contains(url))
                    {
                        // 将URL添加到已爬取的集合中
                        crawledUrls.Add(url);

                        // 在UI线程上更新ListBox，显示已爬取的URL
                        this.Invoke(new Action(() =>
                        {
                            lstUrls.Items.Add(url);
                        }));

                        // 启动异步处理该页面内容的任务
                        pageTasks.Add(ProcessPageAsync(url));
                    }
                } // 等待所有页面的处理任务完成
                await Task.WhenAll(pageTasks);
            }
            catch (Exception ex)
            {
                // 处理异常，例如网络错误或请求失败
                Console.WriteLine($"Error processing search URL {searchurl}: {ex.Message}");
            }
        }


        // 处理单个页面的内容，提取电话号码
        private async Task ProcessPageAsync(string url)
        {
            try
            {
                // 发送GET请求获取页面内容
                string pageContent = await httpClient.GetStringAsync(url);

                // 从页面内容中提取电话号码列表
                List<string> phones = ExtractPhoneNumbers(pageContent);

                // 遍历每个提取的电话号码
                foreach (var phone in phones)
                {
                    // 将电话号码及其关联的URL添加到字典中
                    phoneNumbers.AddOrUpdate(phone, new List<string> { url }, (key, existingList) =>
                    {
                        // 如果URL不在已有的列表中，添加到列表
                        if (!existingList.Contains(url))
                            existingList.Add(url);
                        return existingList;
                    });

                    // 检查是否已提取到100个电话号码，如果是，停止提取
                    if (phoneNumbers.Count >= 100)
                        break;
                }
            }
            catch (Exception ex)
            {
                // 处理异常，例如无法访问的URL或解析错误
                Console.WriteLine($"Error processing page {url}: {ex.Message}");
            }
        }

        // 从页面内容中提取电话号码列表
        private List<string> ExtractPhoneNumbers(string content)
        {
            List<string> phones = new List<string>();

            // 使用正则表达式匹配电话号码
            // 这里的正则表达式匹配7到15位的数字，根据需要调整
            Regex phoneRegex = new Regex(@"\b\d{7,15}\b");

            // 在页面内容中查找所有匹配的电话号码
            MatchCollection matches = phoneRegex.Matches(content);
            foreach (Match match in matches)
            {
                string phone = match.Value;

                // 将电话号码添加到列表中
                phones.Add(phone);

                // 如果已提取到足够的电话号码，停止提取
                if (phoneNumbers.Count >= 100)
                    break;
            }
            return phones;
        }

        private List<string> ExtraUrls(string html)
        {
            List<string> urls = new List<string>();

            //使用正则表达式匹配以http开头的url
            Regex urlRegex = new Regex(@"https?://[^\s""'<>]+", RegexOptions.IgnoreCase);
            MatchCollection matches = urlRegex.Matches(html);
            foreach (Match match in matches)
            {
                string url = match.Value;

                // 过滤掉搜索引擎自身的链接，避免无效爬取
                if (url.Contains("baidu.com") || url.Contains("bing.com"))
                    continue;

                // 将有效的URL添加到列表中
                urls.Add(url);

                // 如果已提取的URL数量达到50个，停止提取
                if (urls.Count >= 50) // 每个搜索引擎最多处理50个链接
                    break;
            }
            return urls;
        }

        //基于用户输入的关键字生成搜索引擎的url列表
        private List<string> GenerateSearchUrls(string keyword)
        {
            List<string>urls=new List<string>();
            // 百度搜索URL，使用Uri.EscapeDataString编码关键字
            string baiduUrl = $"https://www.baidu.com/s?wd={Uri.EscapeDataString(keyword)}";
            urls.Add(baiduUrl);

            // Bing搜索URL，使用Uri.EscapeDataString编码关键字
            string bingUrl = $"https://www.bing.com/search?q={Uri.EscapeDataString(keyword)}";
            urls.Add(bingUrl);
            return urls;
        }

        private void dgvPhoneNumbers_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {

        }
    }
}
